class_name BuffSystem
extends BaseSystem

## TODO 需要能传参配置一次Remove多少层，而不只是全部移除

class BuffItem:
	var buff_entity:Entity
	var buffs:Array[BaseBuff] = []
	signal observer_action(buff)
	func _init(entity:Entity) -> void:
		buff_entity = entity
		buffs = []
#region 属性
@export_range(0,10) var update_delta = 0.1
@export_range(0,1000) var gc_delta = 10
@export var buffs:Array[BaseBuff] = []
var update_timer:Timer
var gc_timer:Timer
var buff_dict:Dictionary = {}
var buff_entity_dict:Dictionary = {}
#endregion
#region 字段
#endregion
#region 信号
#endregion

#region 基类方法
func init_system(args = null):
	super(args)
	for buff:BaseBuff in buffs:
		buff_dict[buff.buff_id] = buff
	update_timer = Timer.new()
	update_timer.name = "UpdateTimer"
	update_timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
	update_timer.autostart = true
	update_timer.one_shot = false
	update_timer.wait_time = update_delta
	update_timer.timeout.connect(_excute_update)
	add_child(update_timer)
	gc_timer = Timer.new()
	gc_timer.name = "GCTimer"
	gc_timer.process_callback = Timer.TIMER_PROCESS_PHYSICS
	gc_timer.autostart = true
	gc_timer.one_shot = false
	gc_timer.wait_time = gc_delta
	gc_timer.timeout.connect(_excute_gc)
	add_child(gc_timer)
#endregion
#region 公共方法
## 开始监听
func start_observering(entity:Entity,listener:Callable) -> Array[BaseBuff]:
	if not buff_entity_dict.has(entity):
		buff_entity_dict[entity] = BuffItem.new(entity)
	var item:BuffItem = buff_entity_dict[entity]
	if not item.observer_action.is_connected(listener):
		item.observer_action.connect(listener)
	return item.buffs
## 结束监听
func stop_observing(entity:Entity,listener:Callable):
	if not buff_entity_dict[entity]:
		return
	var item:BuffItem = buff_entity_dict[entity]
	if item.observer_action.is_connected(listener):
		item.observer_action.disconnect(listener)
## 根据id得到buff的模版
func get_buff_by_id(id:String) -> BaseBuff:
	if buff_dict.has(id):
		var buff:BaseBuff = buff_dict[id]
		return buff.duplicate(true)
	return null
## provider给agent根据id添加buff
func add_buff_by_id(provier,entity:Entity,id:String,level:int = 1,tags:Array[String] = []):
	if not buff_entity_dict.has(entity):
		buff_entity_dict[entity] = BuffItem.new(entity)
		_add_new_buff_by_id(provier,entity,id,level,tags)
		return
	var item:BuffItem = buff_entity_dict[entity]
	if item.buffs.size() == 0:
		_add_new_buff_by_id(provier,entity,id,level,tags)
		return
	var cur_buffs:Array[BaseBuff] = find_buff_by_id(entity,id)
	if cur_buffs.size() == 0:
		_add_new_buff_by_id(provier,entity,id,level,tags)
	else:
		match cur_buffs[0].conflict_resolution:
			GameEnum.BuffConflictResolution.Separate:
				var is_existed:bool = false
				for buff:BaseBuff in cur_buffs:
					if buff.provider == provier:
						## 处理下额外添加的Tag
						buff.add_buff_tags(tags)
						buff.cur_level += level
						is_existed = true
						continue
				if not is_existed:
					_add_new_buff_by_id(provier,entity,id,level,tags)
			GameEnum.BuffConflictResolution.Combine:
				## 处理下额外添加的Tag
				cur_buffs[0].add_buff_tags(tags)
				cur_buffs[0].cur_level += level
			GameEnum.BuffConflictResolution.Cover:
				remove_buff_by_id(entity,cur_buffs[0].buff_id)
				_add_new_buff_by_id(provier,entity,id,level,tags)
	for buff in item.buffs:
		buff.on_update_buff_list.emit()
func add_buff_by_ids(provier,entity:Entity,ids:Array[String],level:int = 1,tags:Array[String] = []):
	for id in ids:
		add_buff_by_id(provier,entity,id,level,tags)
## provider给agent根据模版添加buff
func add_buff_by_temp(provier,entity:Entity,temp_buff:BaseBuff,level:int = 1,tags:Array[String] = []):
	if not buff_entity_dict.has(entity):
		buff_entity_dict[entity] = BuffItem.new(entity)
		_add_new_buff_by_temp(provier,entity,temp_buff,level,tags)
		return
	var item:BuffItem = buff_entity_dict[entity]
	if item.buffs.size() == 0:
		_add_new_buff_by_temp(provier,entity,temp_buff,level,tags)
		return
	var cur_buffs:Array[BaseBuff] = find_buff_by_id(entity,temp_buff.buff_id)
	if cur_buffs.size() == 0:
		_add_new_buff_by_temp(provier,entity,temp_buff,level,tags)
	else:
		match cur_buffs[0].conflict_resolution:
			GameEnum.BuffConflictResolution.Separate:
				var is_existed:bool = false
				for buff:BaseBuff in cur_buffs:
					if buff.provider == provier:
						## 处理下额外添加的Tag
						buff.add_buff_tags(tags)
						buff.cur_level += level
						is_existed = true
						continue
				if not is_existed:
					_add_new_buff_by_temp(provier,entity,temp_buff,level,tags)
			GameEnum.BuffConflictResolution.Combine:
				## 处理下额外添加的Tag
				cur_buffs[0].add_buff_tags(tags)
				cur_buffs[0].cur_level += level
			GameEnum.BuffConflictResolution.Cover:
				remove_buff_by_id(entity,cur_buffs[0].buff_id)
				_add_new_buff_by_temp(provier,entity,temp_buff,level,tags)
	for buff in item.buffs:
		buff.on_update_buff_list.emit()
## 根据id查找agent对应的buff
func find_buff_by_id(entity:Entity,id:String) -> Array[BaseBuff]:
	var res:Array[BaseBuff] = []
	if buff_entity_dict.has(entity):
		res = buff_entity_dict[entity].buffs.filter(func(buff:BaseBuff):return buff.buff_id == id)
	return res
## 返回agent的所有buff
func get_all_buff(entity:Entity) -> Array[BaseBuff]:
	var res:Array[BaseBuff] = []
	if buff_entity_dict.has(entity):
		res = buff_entity_dict[entity].buffs
	return res
## 根据id移除buff
func remove_buff_by_id(entity:Entity,id:String) -> bool:
	var cur_buffs:Array[BaseBuff] = find_buff_by_id(entity,id)
	if cur_buffs.size() == 0:
		return false
	for buff in cur_buffs:
		remove_buff(entity,buff)
	return true
## 根据buff实例移除buff
func remove_buff(entity:Entity,buff:BaseBuff) -> bool:
	if buff == null:
		return false
	buff.cur_level -= buff.cur_level
	var item:BuffItem = buff_entity_dict[entity]
	if buff.cur_level == 0:
		item.buffs.erase(buff)
	for b in item.buffs:
		b.on_update_buff_list.emit()
	return true
## 根据type移除buff
func remove_buff_by_type(entity:Entity,buff_type:GameEnum.BuffType) -> bool:
	if not buff_entity_dict.has(entity):
		return false
	for buff:BaseBuff in buff_entity_dict[entity].buffs.filter(func(b:BaseBuff):return b.buff_type == buff_type):
		if buff.dispellable == false:
			continue
		buff.cur_level -= buff.cur_level
		if buff.cur_level == 0:
			buff_entity_dict[entity].buffs.erase(buff)
	for buff:BaseBuff in buff_entity_dict[entity].buffs:
		buff.on_update_buff_list.emit()
	return true
## 根据tag移除buff
func remove_buff_by_tag(entity:Entity,buff_tag:String) -> bool:
	if not buff_entity_dict.has(entity):
		return false
	for buff:BaseBuff in buff_entity_dict[entity].buffs:
		if buff.dispellable == false:
			continue
		var remove_count = buff.remove_buff_by_tag(buff_tag)
		if remove_count == 0:
			continue
		buff.cur_level -= remove_count
		if buff.cur_level == 0:
			buff_entity_dict[entity].buffs.erase(buff)
	for buff:BaseBuff in buff_entity_dict[entity].buffs:
		buff.on_update_buff_list.emit()
	return true
## 根据group移除buff
func remove_buff_by_group(entity:Entity,buff_group:GameEnum.BuffGroup) -> bool:
	if not buff_entity_dict.has(entity):
		return false
	for buff:BaseBuff in buff_entity_dict[entity].buffs.filter(func(b:BaseBuff):return b.buff_group & buff_group > 0):
		if buff.dispellable == false:
			continue
		buff.cur_level -= buff.cur_level
		if buff.cur_level == 0:
			buff_entity_dict[entity].buffs.erase(buff)
	for buff:BaseBuff in buff_entity_dict[entity].buffs:
		buff.on_update_buff_list.emit()
	return true
## 移除agent的所有buff
func remove_all_buff(entity:Entity):
	if not buff_entity_dict.has(entity):
		return false
	for buff:BaseBuff in buff_entity_dict[entity].buffs:
		buff.cur_level -= buff.cur_level
	buff_entity_dict[entity].buffs.clear()
	buff_entity_dict.erase(entity)
	return true
#endregion
#region 私有方法
func _add_new_buff_by_id(provier,target_entity:Entity,id:String,level:int,tags:Array[String] = []):
	var buff:BaseBuff = buff_dict[id].duplicate(true)
	buff.init_buff(provier,target_entity)
	## 处理下额外添加的Tag
	buff.add_buff_tags(tags)
	var item:BuffItem = buff_entity_dict[target_entity]
	item.buffs.append(buff)
	buff.residual_duration = buff.max_duration
	buff.cur_level = level
	buff.on_get_buff.emit()
	item.observer_action.emit(buff)
func _add_new_buff_by_temp(provier,target_entity:Entity,temp_buff:BaseBuff,level:int,tags:Array[String] = []):
	temp_buff.init_buff(provier,target_entity)
	## 处理下额外添加的Tag
	temp_buff.add_buff_tags(tags)
	var item:BuffItem = buff_entity_dict[target_entity]
	item.buffs.append(temp_buff)
	temp_buff.residual_duration = temp_buff.max_duration
	temp_buff.cur_level = level
	temp_buff.on_get_buff.emit()
	item.observer_action.emit(temp_buff)
func _excute_update():
	for item:BuffItem in buff_entity_dict.values():
		for buff:BaseBuff in item.buffs:
			if buff.cur_level > 0 and buff.cur_buff_entity:
				buff.on_update_buff.emit()
				buff.residual_duration -= update_delta
	for agent in buff_entity_dict:
		var item:BuffItem = buff_entity_dict[agent]
		for i in range(item.buffs.size()-1,-1,-1):
			var buff:BaseBuff = item.buffs[i]
			if buff.cur_level == 0:
				remove_buff(agent,buff)
				continue
			if buff.residual_duration <= 0:
				buff.cur_level -= buff.demotion
				if buff.cur_level == 0:
					remove_buff(agent,buff)
					continue
				else:
					buff.residual_duration = buff.max_duration
func _excute_gc():
	var entitys:Array[Node2D] = []
	for entity in buff_entity_dict:
		if entity == null:
			entitys.append(entity)
		var item:BuffItem = buff_entity_dict[entity]
		if item.buffs.size() == 0 and item.observer_action.get_connections().size() == 0:
			entitys.append(entity)
	for entity in entitys:
		buff_entity_dict.erase(entity)
#endregion
#region 生命周期函数
#endregion
